x11: keep track of the screen pixel size by calculating the bounding box of monitors
authorCarlos Garnacho <carlosg@gnome.org>
Fri, 22 Nov 2013 17:33:02 +0000 (18:33 +0100)
committerCarlos Garnacho <carlosg@gnome.org>
Mon, 25 Nov 2013 16:19:46 +0000 (17:19 +0100)
This is so we always have the latest information given by XRandR (or other), and not
rely on Core protocol information that might not have been updated yet.

This is specially visible when a monitor is connected (less frequent) or disconnected
(much more frequent), callbacks on GdkScreen::monitors-changed that call
gdk_screen_get_width/height() could get the screen size previous to the monitor
rearrangement.

So in order to fix this, keep track of the latest monitors information, and calculate
the bounding box in order to know the screen size.

https://bugzilla.gnome.org/show_bug.cgi?id=715029

gdk/x11/gdkscreen-x11.c
gdk/x11/gdkscreen-x11.h

index c2d7c881a7b015d0e9e2db88d411517f3f865a5f..6b098340d62c8848e4f3c732d09a74dd1e4e09a4 100644 (file)
@@ -96,13 +96,13 @@ gdk_x11_screen_get_display (GdkScreen *screen)
 static gint
 gdk_x11_screen_get_width (GdkScreen *screen)
 {
-  return WidthOfScreen (GDK_X11_SCREEN (screen)->xscreen) / GDK_X11_SCREEN (screen)->window_scale;
+  return GDK_X11_SCREEN (screen)->width / GDK_X11_SCREEN (screen)->window_scale;
 }
 
 static gint
 gdk_x11_screen_get_height (GdkScreen *screen)
 {
-  return HeightOfScreen (GDK_X11_SCREEN (screen)->xscreen) / GDK_X11_SCREEN (screen)->window_scale;
+  return GDK_X11_SCREEN (screen)->height / GDK_X11_SCREEN (screen)->window_scale;
 }
 
 static gint
@@ -916,8 +916,8 @@ _gdk_x11_screen_get_edge_monitors (GdkScreen *screen,
                                    gint      *right)
 {
   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
-  gint          top_most_pos = HeightOfScreen (GDK_X11_SCREEN (screen)->xscreen);
-  gint          left_most_pos = WidthOfScreen (GDK_X11_SCREEN (screen)->xscreen);
+  gint          top_most_pos = x11_screen->height;
+  gint          left_most_pos = x11_screen->width;
   gint          bottom_most_pos = 0;
   gint          right_most_pos = 0;
   gint          monitor_num;
@@ -1046,6 +1046,30 @@ init_multihead (GdkScreen *screen)
                         HeightOfScreen (x11_screen->xscreen));
 }
 
+static void
+update_bounding_box (GdkScreen *screen)
+{
+  GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
+  gint i, x1, y1, x2, y2;
+
+  x1 = y1 = G_MAXINT;
+  x2 = y2 = G_MININT;
+
+  for (i = 0; i < x11_screen->n_monitors; i++)
+    {
+      GdkX11Monitor *monitor;
+
+      monitor = &x11_screen->monitors[i];
+      x1 = MIN (x1, monitor->geometry.x);
+      y1 = MIN (y1, monitor->geometry.y);
+      x2 = MAX (x2, monitor->geometry.x + monitor->geometry.width);
+      y2 = MAX (y2, monitor->geometry.y + monitor->geometry.height);
+    }
+
+  x11_screen->width = x2 - x1;
+  x11_screen->height = y2 - y1;
+}
+
 GdkScreen *
 _gdk_x11_screen_new (GdkDisplay *display,
                     gint        screen_number) 
@@ -1087,7 +1111,8 @@ _gdk_x11_screen_new (GdkDisplay *display,
   
   _gdk_x11_screen_init_visuals (screen);
   _gdk_x11_screen_init_root_window (screen);
-  
+  update_bounding_box (screen);
+
   return screen;
 }
 
@@ -1186,11 +1211,13 @@ process_monitors_change (GdkScreen *screen)
                       x11_screen->monitors, x11_screen->n_monitors) ||
     x11_screen->primary_monitor != primary_monitor;
 
-
   free_monitors (monitors, n_monitors);
 
   if (changed)
-    g_signal_emit_by_name (screen, "monitors-changed");
+    {
+      update_bounding_box (screen);
+      g_signal_emit_by_name (screen, "monitors-changed");
+    }
 }
 
 void
index ce8598e11e1b875904c65a0816999a911cac6bdc..87be0aa59be066abf42d0667ac82b4050e8b5e20 100644 (file)
@@ -47,6 +47,9 @@ struct _GdkX11Screen
   GdkX11Monitor *monitors;
   gint primary_monitor;
 
+  gint width;
+  gint height;
+
   gint window_scale;
   gboolean fixed_window_scale;